package resource

import (
	"operator/pkg/util"
	"sync"
)

type ResourceMap struct {
	data         map[string]*PodResource
	mu           sync.RWMutex
	resourceDict map[ResourceString][]Resource
}

func (r *ResourceMap) String() string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	m := map[string]interface{}{
		"data":     r.data,
		"resource": r.resourceDict,
	}
	return util.JsonEncode(m)
}

func (r *ResourceMap) Resource() string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return util.JsonEncode(r.resourceDict)
}

// Add
//similar key下的value是否与给定的相同
func (r *ResourceMap) Add(key string, value *PodResource) (similar bool, err error) {
	r.mu.RLock()
	old, ok := r.data[key]
	r.mu.RUnlock()

	r.mu.Lock()
	defer r.mu.Unlock()
	m := value.ToMap(key)
	for k, v := range m {
		if d, ok := r.resourceDict[k]; ok {
			list := make([]Resource, 0, 10)
			uids := make(map[string]struct{})
			for _, i := range v {
				for _, j := range d {
					if j.Uid == i.Uid {
						uids[j.Uid] = struct{}{}
						continue
					}
				}
				list = append(list, i)
			}
			for _, j := range d {
				if _, ok := uids[j.Uid]; ok {
					continue
				}
				list = append(list, j)
			}

			r.resourceDict[k] = list
		} else {
			r.resourceDict[k] = v
		}
	}

	if !ok {
		r.data[key] = value

		return false, nil
	}
	if util.MD5String(old.Resource) == util.MD5String(value.Resource) && old.IP == value.IP {
		similar = true
		return
	}

	r.data[key] = value

	return
}

func (r *ResourceMap) Del(key string) (has bool, err error) {
	r.mu.RLock()
	resources, ok := r.data[key]
	r.mu.RUnlock()
	if !ok {
		return false, nil
	}

	r.mu.Lock()
	defer r.mu.Unlock()
	delete(r.data, key)

	m := resources.ToMap(key)
	deleteList := make(map[string]struct{})
	for k, v := range m {
		for _, i := range v {
			deleteList[i.Uid] = struct{}{}
		}
		if d, ok := r.resourceDict[k]; ok {
			newResouce := make([]Resource, 0, 10)
			for _, j := range d {
				if _, ok := deleteList[j.Uid]; ok {
					continue
				}
				newResouce = append(newResouce, j)
			}
			if len(newResouce) == 0 {
				delete(r.resourceDict, k)
				continue
			}
			r.resourceDict[k] = newResouce
		}
	}

	return true, nil
}

func NewResourceMap() *ResourceMap {
	r := &ResourceMap{
		data:         map[string]*PodResource{},
		mu:           sync.RWMutex{},
		resourceDict: map[ResourceString][]Resource{},
	}
	return r
}
